package com.thghh.fsbrowser.fs;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPSClient;

import com.thghh.fsbrowser.annotation.FileSystemType;

/**
 * com.thghh.fsbrowser.fs.FTPFileSystem
 * 
 * @author Zhikang.Peng
 * @date 2018-09-2511:03:55
 * @since 1.0
 */
@FileSystemType()
public class FTPFileSystem extends CommonFileSystem implements IFileSystem {

	public static final Log log = LogFactory.getLog(FTPFileSystem.class);
	private final ExpiringCache fileCache = new ExpiringCache();

	/**
	 * The protocol to use (ftp, http, nntp, ... etc.) .
	 * 
	 * @serial
	 */
	private String protocol;

	/**
	 * The host name to connect to.
	 * 
	 * @serial
	 */
	private String host;

	/**
	 * The protocol port to connect to.
	 * 
	 * @serial
	 */
	private int port = -1;

	private String user;
	private String pwd;

	private FTPClient ftpClient;
	private int replyCode;

	public FTPFileSystem() {
		this("ftp", "127.0.0.1", 21, "sa", "sa");
	}

	public FTPFileSystem(String host, int port, String user, String pwd) {
		this("ftp", host, port, user, pwd);
	}

	public FTPFileSystem(String protocol, String host, int port, String user, String pwd) {
		super();
		this.protocol = protocol;
		this.host = host;
		this.port = port;
		this.user = user;
		this.pwd = pwd;

		ftpClient = initialize(host, port, user, pwd);
	}

	private FTPClient initialize(String host, int port, String user, String pwd) {
		FTPClient ftpClient = null;
		try {
			if (this.protocol.equals("ftp")) {
				ftpClient = new FTPClient();
				ftpClient.setControlEncoding("utf-8");
				ftpClient.connect(host, port); // 连接ftp服务器
				ftpClient.login(user, pwd); // 登录ftp服务器
				replyCode = ftpClient.getReplyCode(); // 是否成功登录服务器
			} else {
				ftpClient = new FTPSClient();
				ftpClient.setControlEncoding("utf-8");
				ftpClient.connect(host, port); // 连接ftp服务器
				ftpClient.login(user, pwd); // 登录ftp服务器
				replyCode = ftpClient.getReplyCode(); // 是否成功登录服务器
			}
		} catch (SocketException e) {
			log.error(e);
		} catch (IOException e) {
			log.error(e);
		}
		return ftpClient;
	}

	@Override
	public boolean exists(FilePath filePath) {
		FilePath[] f = filePath
				.listFiles(/* (FilePath p) -> (p.compareTo(filePath) == 0) */);
		return f != null && f.length > 0;
	}

	@Override
	public boolean isDirectory(FilePath filePath) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isFile(FilePath filePath) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public long getLastModifiedTime(FilePath filePath) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public long getLength(FilePath filePath) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public boolean createNewFile(FilePath filePath) throws IOException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean delete(FilePath filePath) {
		try {
			ftpClient.changeWorkingDirectory(filePath.getParent());
			return ftpClient.deleteFile(filePath.getPath());
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

	@Override
	public String[] list(FilePath filePath) {
		try {
			FTPFile[] ftpFiles = ftpClient.listFiles(filePath.getPath());
			String[] files = new String[ftpFiles.length];
			for (int i = 0; i < ftpFiles.length; i++) {
				files[i] = ftpFiles[i].getName();
			}
			return files;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public boolean createDirectory(FilePath filePath) {
		try {
			ftpClient.changeWorkingDirectory(filePath.getParent());
			return ftpClient.makeDirectory(filePath.getPath());
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

	@Override
	public boolean rename(FilePath source, FilePath dest) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public int compare(FilePath fp1, FilePath fp2) {
		return fp1.getPath().compareTo(fp2.getPath());
	}

	@Override
	public InputStream open(FilePath filePath) throws IOException {
		// 设置上传的路径
		ftpClient.changeWorkingDirectory(filePath.getParent());
		// 修改上传文件的格式
		ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
		return new FSInputStream(ftpClient.retrieveFileStream(filePath.getPath()), this);
	}

	@Override
	public OutputStream create(FilePath filePath) throws IOException {
		// 设置上传的路径
		ftpClient.changeWorkingDirectory(filePath.getParent());
		// 修改上传文件的格式
		ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
		return new FSOutputStream(ftpClient.storeFileStream(filePath.getPath()), this);
	}

	private FTPFile getFTPFile(FilePath filePath) throws IOException {
		if (filePath == null) {
			new FileNotFoundException("File is not found.");
		}
		if (getDefaultParent().equals(filePath.getPath())) {
			FTPFile ftpFile = new FTPFile();
			ftpFile.setType(FTPFile.DIRECTORY_TYPE);
			ftpFile.setName(getDefaultParent());
			ftpFile.setUser(user);
			return ftpFile;
		}
		FTPFile[] ftpFiles = ftpClient.listFiles(filePath.getParentFile().getPath());
		for (FTPFile ftpFile : ftpFiles) {
			if (ftpFile.getName().equals(filePath.getPath())) {
				return ftpFile;
			}
		}

		return null;
	}

	@Override
	public boolean checkAccess(FilePath f, int access) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean setPermission(FilePath f, int access, boolean enable, boolean owneronly) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean setLastModifiedTime(FilePath f, long time) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean setReadOnly(FilePath f) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public FilePath[] listRoots() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public long getSpace(FilePath f, int t) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int hashCode(FilePath f) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public String tmpdir() {
		return this.getDefaultParent() + user + File.pathSeparator + "tempdir";
	}

	@Override
	public void close() throws IOException {

	}

	@Override
	public boolean isConnected() {
		return false;
	}

}
